GW_SHOWTYPE_W = 1
GW_SHOWTYPE_P = 2
GW_SHOWTYPE_M = 3
GW_SHOWTYPE_ALL = 4

GW_RCD_IDX_WSCO = 0 // 看word的分数
GW_RCD_IDX_WOK  = 1 // 看word的ok次数
GW_RCD_IDX_WNOK = 2 // 看word的no_ok次数
GW_RCD_IDX_PSCO = 3
GW_RCD_IDX_POK  = 4
GW_RCD_IDX_PNOK = 5
GW_RCD_IDX_MSCO = 6
GW_RCD_IDX_MOK  = 7
GW_RCD_IDX_MNOK = 8

GW_WORDINFO_ID      = 0
GW_WORDINFO_WORD    = 1
GW_WORDINFO_PNC     = 2
GW_WORDINFO_PNC_NUM = 3
GW_WORDINFO_MEAN    = 4
GW_WORDINFO_TYPE    = 5
GW_WORDINFO_HINT    = 7

GW_OK_SCORE = 100
GW_OK_OFFSET = 8
GW_NOOK_OFFSET = 5

/**
 * GetWord类：接下来要展示的单词以及展示类型
 * 思路：
 *      所有单词打乱排序后，用链表组织起来
 *      每个单词的每种展示方式都有一个评分，评分达标后，换成下一种展示方式
 *      第一次就OK，则当前展示方法评分达标
 *      如果不OK，延后若干次（可调）后，重复考察
 *      非第一次OK，累加少量评分（可调），直到评分达标
 *      单词的所有展示方式都达标后，从链表中删除？
 */
function GetWord(words_info) {
    /**
     * 根据id当前的record，判断接下来的展示类型
     * @param id : 单词id
     * @returns 成功时返回展示类型，否则返回null
     */
    this.get_next_show_type = function(id) {
        if(this.record[id][GW_RCD_IDX_WSCO] < GW_OK_SCORE) { return GW_SHOWTYPE_W; }
        if(this.record[id][GW_RCD_IDX_PSCO] < GW_OK_SCORE) { return GW_SHOWTYPE_P; }
        if(this.record[id][GW_RCD_IDX_MSCO] < GW_OK_SCORE) { return GW_SHOWTYPE_M; }
        return null;
    }

    /**
     * 根据id对应的word_info生成最初的record值，有些值会被置为满分
     * @param id : 单词id
     */
    this.gen_init_record_item = function(id) {
        var record_item = [0,0,0,0,0,0,0,0,0];
        var info = this.word_infos[id];
        // 没有汉字的单词，没有发音，此时不考发音
        // 汉字只考word
        if(info[GW_WORDINFO_TYPE] == "T_W"
        || info[GW_WORDINFO_TYPE] == "CC") {
            record_item[GW_RCD_IDX_PSCO] = GW_OK_SCORE;
            record_item[GW_RCD_IDX_MSCO] = GW_OK_SCORE;
        }
        else if(info[GW_WORDINFO_TYPE] == "T_M"
        || info[GW_WORDINFO_TYPE] == "SENT"
        || info[GW_WORDINFO_TYPE] == 'GRAM') {
            record_item[GW_RCD_IDX_WSCO] = GW_OK_SCORE;
            record_item[GW_RCD_IDX_PSCO] = GW_OK_SCORE;
        }
        else if(info[GW_WORDINFO_TYPE] == "T_WM"
        || info[GW_WORDINFO_TYPE] == "PHRS") {
            record_item[GW_RCD_IDX_PSCO] = GW_OK_SCORE;
        }
        else if(info[GW_WORDINFO_TYPE] == "T_WP") {
            record_item[GW_RCD_IDX_MSCO] = GW_OK_SCORE;
        }
        if(info[GW_WORDINFO_PNC] == '') {
            record_item[GW_RCD_IDX_PSCO] = GW_OK_SCORE;
        }
        return record_item;
    }

    this.list = new List();   // [[id,show_type] ...]
    this.record = {}; // {id:[score, w_ok_cnt, w_nook_cnt, p_ok_cnt, p_nook_cnt, m_ok_cnt, m_nook_cnt]}
    this.word_infos = {}; // {id:word_info}

    // 对words_info打乱顺序
    for(var i = 0; i < words_info.length; i++) {
        var new_idx = Math.floor(Math.random() * 1000000 % words_info.length);
        new_idx = (i + new_idx) % words_info.length;
        var tmp = words_info[i];
        words_info[i] = words_info[new_idx]
        words_info[new_idx] = tmp;
    }

    // 把words_info添加至链表
    words_info.forEach(info => {
        this.word_infos[info[GW_WORDINFO_ID]] = info;
        var record = this.gen_init_record_item(info[GW_WORDINFO_ID]);
        this.record[info[GW_WORDINFO_ID]] = record;
        var show_type = this.get_next_show_type(info[GW_WORDINFO_ID]);
        this.list.push_back([info[GW_WORDINFO_ID], show_type]);
    });
    this.cur_ptr = this.list.get_head_ptr(); // cur_ptr相当于list的迭代器

    // 有数据时返回[word_info, show_type]
    // 无数据时返回null
    this.get = function() {
        if(this.cur_ptr == null) {
            return null;
        }
        var node_data = this.list.data[this.cur_ptr].data;
        var word_id = node_data[0];
        var show_type = node_data[1];
        var word_info = this.word_infos[word_id];
        this.cur_ptr = this.list.data[this.cur_ptr].next;
        this.list.pop_front();
        return [word_info, show_type];
    }

    /**
     * 更新单词的学习状态
     * @param id 单词id
     * @param show_type 显示类型
     * @param is_ok 会不会
     * @return 完全掌握返回true，否则返回false
     */
    this.update = function(id, show_type, is_ok) {
        if(is_ok == true) {
            if(this.is_word_ok(id) == true) {
                return true;
            }
            switch(show_type) {
            case GW_SHOWTYPE_W:
                this.record[id][GW_RCD_IDX_WOK] += 1;
                this.record[id][GW_RCD_IDX_WSCO] += this.get_score_by_nook_cnt(this.record[id][GW_RCD_IDX_WNOK]);
                if(this.record[id][GW_RCD_IDX_WSCO] < GW_OK_SCORE) {
                    this.list.insert([id, GW_SHOWTYPE_W], this.cur_ptr, GW_OK_OFFSET);
                }
                else {
                    var next_show_type = this.get_next_show_type(id);
                    if(next_show_type == null) {
                        return true; // 已经完全掌握
                    }
                    this.list.insert([id, next_show_type], this.cur_ptr, GW_OK_OFFSET);
                }
                break;
            case GW_SHOWTYPE_P:
                this.record[id][GW_RCD_IDX_POK] += 1;
                this.record[id][GW_RCD_IDX_PSCO] += this.get_score_by_nook_cnt(this.record[id][GW_RCD_IDX_PNOK]);
                if(this.record[id][GW_RCD_IDX_PSCO] < GW_OK_SCORE) {
                    this.list.insert([id, GW_SHOWTYPE_P], this.cur_ptr, GW_OK_OFFSET);
                }
                else {
                    var next_show_type = this.get_next_show_type(id);
                    if(next_show_type == null) {
                        return true; // 已经完全掌握
                    }
                    this.list.insert([id, next_show_type], this.cur_ptr, GW_OK_OFFSET);
                }
                break;
            case GW_SHOWTYPE_M:
                this.record[id][GW_RCD_IDX_MOK] += 1;
                this.record[id][GW_RCD_IDX_MSCO] += this.get_score_by_nook_cnt(this.record[id][GW_RCD_IDX_MNOK]);
                if(this.record[id][GW_RCD_IDX_MSCO] >= GW_OK_SCORE) {
                    return true;
                }
                this.list.insert([id, GW_SHOWTYPE_M], this.cur_ptr, GW_OK_OFFSET);
            }
        }
        else { // is_ok == false
            switch(show_type) {
            case GW_SHOWTYPE_W:
                this.record[id][GW_RCD_IDX_WNOK] += 1;
                this.record[id][GW_RCD_IDX_WSCO] = 0;
                this.list.insert([id, GW_SHOWTYPE_W], this.cur_ptr, GW_NOOK_OFFSET);
                break;
            case GW_SHOWTYPE_P:
                this.record[id][GW_RCD_IDX_PNOK] += 1;
                this.record[id][GW_RCD_IDX_PSCO] = 0;
                this.list.insert([id, GW_SHOWTYPE_P], this.cur_ptr, GW_NOOK_OFFSET);
                break;
            case GW_SHOWTYPE_M:
                this.record[id][GW_RCD_IDX_MNOK] += 1;
                this.record[id][GW_RCD_IDX_MSCO] = 0;
                this.list.insert([id, GW_SHOWTYPE_M], this.cur_ptr, GW_NOOK_OFFSET);
                break;
            }
        }
        return false;
    }

    // 设置某个单词已经完全掌握
    this.set_word_all_ok = function(id) {
        this.record[id][GW_RCD_IDX_WSCO] = GW_OK_SCORE;
        this.record[id][GW_RCD_IDX_PSCO] = GW_OK_SCORE;
        this.record[id][GW_RCD_IDX_MSCO] = GW_OK_SCORE;
    }

    this.get_show_type = function(id) {
        var rcd = this.record[id]
        if(rcd[GW_RCD_IDX_WSCO] < GW_OK_SCORE) {
            return GW_SHOWTYPE_W;
        }
        if(rcd[GW_RCD_IDX_PSCO] < GW_OK_SCORE) {
            return GW_SHOWTYPE_P;
        }
        if(rcd[GW_RCD_IDX_MSCO] < GW_OK_SCORE) {
            return GW_SHOWTYPE_M;
        }
    }

    this.is_word_ok = function(id) {
        if(this.record[id][GW_RCD_IDX_WSCO] >= GW_OK_SCORE
        && this.record[id][GW_RCD_IDX_PSCO] >= GW_OK_SCORE
        && this.record[id][GW_RCD_IDX_MSCO] >= GW_OK_SCORE) {
            return true;
        }
        return false;
    }

    /**
     * 根据不会的次数，计算如果当前ok时，应该加多少分数
     * @param {*} nook_cnt 
     * @returns 分数
     */
    this.get_score_by_nook_cnt = function(nook_cnt) {
        if(nook_cnt == 0) { return 100; }
        if(nook_cnt <= 3) { return 50;  }
        return 34;
    }
}

